/*
 * IContactHelpers.java
 * 
 * Version information
 * 
 * Mar 31, 2006
 * 
 * Copyright (c) AmSoft Systems, 2006
 */
package net.amsoft.iservice.icontact.util;

import java.util.List;

import net.amsoft.iservice.icontact.hibernate.IBroker;
import net.amsoft.iservice.icontact.hibernate.IContactObject;
import net.amsoft.iservice.icontact.hibernate.Message;
import net.amsoft.iservice.icontact.hibernate.Subscriber;
import net.amsoft.iservice.icontact.hibernate.Synonym;
import net.amsoft.iservice.icontact.hibernate.dataObject.MessageData;
import net.amsoft.iservice.icontact.service.IContact;
import net.amsoft.iservice.util.HibernateUtil;
import net.amsoft.iservice.util.exception.IServiceException;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;

/**
 * ICOntactHelpers class is designed to facilitate the operations related to
 * hibernate, it is used to fetch different data objects which are used to
 * perform different database operations. The APIs provided in the
 * IContactHelpers class are used in the service layer of the IContact Service.
 * 
 */

public class IContactHelpers {

	private static Logger oLogger = Logger.getLogger(IContact.class);

	/**
	 * API returns object of class cClass, fetch() uses id and returns a general
	 * object to cClass.
	 * 
	 * @param cClass
	 *            fetch data object of this class
	 * @param id
	 *            use this id to fetch object
	 * @param oSession
	 *            hibernate session for user's current requests
	 * @return Object object of cClass
	 */
	public static Object fetch(Class cClass, Long id, Session oSession) {
		oLogger.info("fetch() : entry : fetching Object");
		IContactObject oIContactObject = (IContactObject) oSession.load(cClass,
				id);
		if (oIContactObject != null)
			oIContactObject.update();
		oLogger.info("fetch() : exit");
		return (oIContactObject);
	}

	/**
	 * this is a special api to fetch the data object of broker using
	 * sServerName
	 * 
	 * @param oSession
	 *            A Map that the application will preserve between the current
	 *            user's requests
	 * @param oTransaction
	 *            Hibernate Transaction for current session
	 * @param sServerName
	 *            used to fetch the broker data object
	 * @return IBroker data object of IBroker class
	 */
	public static IBroker fetchIBroker(Session oSession,
			Transaction oTransaction, String sServerName) {
		oLogger.info("fetchIBroker() : entry with data : ServerName="
				+ sServerName);
		IBroker oIBroker = new IBroker();

		oIBroker = (IBroker) oSession.createCriteria(IBroker.class).add(
				Expression.eq("serverName", sServerName)).add(
				Expression.eq("state", Integer
						.valueOf(IContactConstants.ACTIVE))).uniqueResult();
		oLogger
				.info("fetchIBroker() : exit, return Broker Object: "
						+ oIBroker);
		return (oIBroker);
	}

	/**
	 * This API is used to fetch the count of the synonyms
	 * 
	 * @param sSynonym
	 *            object whose synonym count is to be fetched
	 * @param oSession
	 *            A Map that the application will preserve between the current
	 *            user's requests
	 * @return int count of the synonyms for this synonym object
	 */
	public static int fetchMsgBySynCount(Synonym sSynonym, Session oSession) {
		oLogger.info("fetchMsgBySynCount() : entry");
		Criteria crit = oSession.createCriteria(Message.class);
		crit.add(Expression.eq("synonym", sSynonym));
		crit.add(Expression.isNull("parent"));
		crit.add(Expression.eq("state", Integer
				.valueOf(IContactConstants.ACTIVE)));
		crit.setProjection(Projections.rowCount());
		Integer count = (Integer) crit.list().iterator().next();
		oLogger.info("fetchMsgBySynCount() : exit, return Message Count: "
				+ count.intValue());
		return (count.intValue());
	}

	/**
	 * This API is used to fetch the List of Messsage related to a given
	 * synonym. The list consists of all messages from offset to limit.
	 * 
	 * @param sSynonym
	 *            The synonym object whose messages are to be fetched
	 * @param offset
	 *            It should be the first message in the list
	 * @param limit
	 *            Message list should have last message
	 * @param oSession
	 *            A Map that the application will preserve between the current
	 *            user's requests
	 * @param oTransaction
	 *            Hibernate Transaction for current session
	 * @return List of Messages related to given Synonym
	 */
	public static List fetchMsgBySyn(Synonym sSynonym, int offset, int limit,
			Session oSession, Transaction oTransaction) {
		oLogger.info("fetchMsgBySyn() : entry with data : Synonym="
				+ sSynonym.getName() + ", offset=" + offset + ", limit="
				+ limit);
		Criteria crit = oSession.createCriteria(Message.class);
		crit.add(Expression.eq("synonym", sSynonym));
		crit.add(Expression.isNull("parent"));
		crit.add(Expression.eq("state", Integer
				.valueOf(IContactConstants.ACTIVE)));
		crit.addOrder(Order.desc("creationTime"));
		crit.setFirstResult(offset);
		crit.setMaxResults(limit);
		List lMessages = crit.list();
		oLogger
				.info("fetchMsgBySyn() : exit, return Message List:"
						+ lMessages);
		return (lMessages);
	}

	/**
	 * Get all the messages available in the thread of given message. It may
	 * consist of messages which were sent as the replies also. It first fetches
	 * the Message object using MessageData and then retrieves the count of
	 * messages in current messages.
	 * 
	 * @param oMsgData
	 *            Message Data gives information of the parent message
	 * @param oSession
	 *            A Map that the application will preserve between the current
	 *            user's requests
	 * @return int count of messages
	 */
	public static int fetchMsgByMsgCount(MessageData oMsgData, Session oSession) {
		oLogger.info("fetchMsgByMsgCount() : entry, GIN: "
				+ oMsgData.getSenderIName());
		Message oMsg = (Message) fetch(Message.class, oMsgData.getId(),
				oSession);
		Criteria crit = oSession.createCriteria(Message.class);
		crit.add(Expression.eq("parent", oMsg));
		crit.add(Expression.eq("state", Integer
				.valueOf(IContactConstants.ACTIVE)));
		crit.setProjection(Projections.rowCount());
		Integer count = (Integer) crit.list().iterator().next();
		oLogger.info("fetchMsgByMsgCount() : exit, return Message Count: "
				+ count.intValue());
		return (count.intValue());
	}

	/**
	 * Gets the list of messages available in the thread of given message. It
	 * may consist of messages which were sent as the replies also. It first
	 * fetches the Message object using MessageData and then retrieves the
	 * messages from offset to limit.
	 * 
	 * @param oMsgData
	 *            Message Data gives information of the parent message
	 * @param offset
	 *            It should be the first message in the list
	 * @param limit
	 *            Message list should have last message
	 * @param oSession
	 *            A Map that the application will preserve between the current
	 *            user's requests
	 * @param oTransaction
	 *            Hibernate Transaction for current session
	 * @return List of messages
	 */
	public static List fetchMsgByMsg(MessageData oMsgData, int offset,
			int limit, Session oSession, Transaction oTransaction) {
		oLogger.info("fetchMsgByMsg() : entry with data : MessageData.Synonym="
				+ oMsgData.getSynonym() + ", offset=" + offset + ", limit="
				+ limit);
		Message oMsg = (Message) fetch(Message.class, oMsgData.getId(),
				oSession);
		Criteria crit = oSession.createCriteria(Message.class);
		crit.add(Expression.eq("parent", oMsg));
		crit.add(Expression.eq("state", Integer
				.valueOf(IContactConstants.ACTIVE)));
		crit.addOrder(Order.desc("creationTime"));
		//crit.addOrder(Order.asc("creationTime"));
		crit.setFirstResult(offset);
		crit.setMaxResults(limit);
		List lMessages = crit.list();
		oLogger.info("fetchMsgByMsg() :  : exit, return Message List:"
				+ lMessages);
		return (lMessages);
	}

	/**
	 * Gets a Message using its hash value and its state.
	 * 
	 * @param sHash
	 *            The Hash value of the message
	 * @param iState
	 *            the state of the message
	 * @param oSession
	 *            A Map that the application will preserve between the current
	 *            user's requests
	 * @return Message object
	 */
	public static Message fetchMsgByHashAndState(String sHash, int iState,
			Session oSession) {
		oLogger.info("fetchMsgByHashAndState() : entry with data : Hash="
				+ sHash + ", state=" + iState);
		Criteria crit = oSession.createCriteria(Message.class);
		crit.add(Expression.eq("hash", sHash));
		crit.add(Expression.eq("state", Integer.valueOf(iState)));
		Message oMsg = (Message) crit.uniqueResult();
		oLogger
				.info("fetchMsgByHashAndState() : exit, return Message: "
						+ oMsg);
		return (oMsg);
	}

	/**
	 * This API fetches the subscriber of the given global i-number.
	 * 
	 * @param sGIN
	 *            The global i-number whose Subscriber is to be fetched
	 * @param oSession
	 *            A Map that the application will preserve between the current
	 *            user's requests
	 * @return Subscriber object of the given global i-number
	 */
	public static Subscriber fetchSubscriber(String sGIN, Session oSession) {
		oLogger.info("fetchSubscriber() : entry with data : GIN=" + sGIN);
		Synonym oGINSyn = (Synonym) oSession.createCriteria(Synonym.class).add(
				Expression.eq("name", sGIN)).add(
				Expression.eq("state", Integer
						.valueOf(IContactConstants.ACTIVE))).uniqueResult();
		Subscriber oSub = oGINSyn.getSubscriber();
		oLogger.info("fetchSubscriber() : exit, return Subscriber object: "
				+ oSub);
		return (oSub);
	}

	/**
	 * The API fetches the Synonym using the given name of the synonym.
	 * 
	 * @param sName
	 *            Name of the synonym to be fetched
	 * @param oSession
	 *            Hibernate session on which beginTransaction() is already
	 *            called
	 * @return Synonym object
	 * @throws IServiceException
	 */
	public static Synonym fetchSynonym(String sName, Session oSession)
			throws IServiceException {
		oLogger.info("fetchSynonym() : entry with data : Name=" + sName);
		try {
			Synonym oSyn = new Synonym();
			oSyn = (Synonym) oSession.createCriteria(Synonym.class).add(
					Expression.eq("name", sName)).add(
					Expression.eq("state", Integer
							.valueOf(IContactConstants.ACTIVE))).uniqueResult();
			oLogger.info("fetchSynonym() : exit, return Synonym Object: "
					+ oSyn + ", of " + oSyn.getName());
			return (oSyn);
		} catch (Exception e) {
			oLogger.error("fetchSynonym(): exception: " + e.getMessage());
			if (e instanceof IServiceException) {
				throw (IServiceException) e;
			} else {
				throw new IServiceException(oLogger, 1002);
			}
		}
	}

	/**
	 * Gets the List of all Synonyms using the subscriber id.
	 * 
	 * @param lSubscriberId
	 * @return List of all synonyms of the given subscriber
	 */
	public static List fetchSynonymBySubscriber(Long lSubscriberId) {
		oLogger
				.info("fetchSynonymBySubscriber() : entry with data : SubscriberId="
						+ lSubscriberId);
		Session oSession = HibernateUtil.getSessionFactory()
				.getCurrentSession();
		oSession.beginTransaction();
		Criteria crit = oSession.createCriteria(Synonym.class);
		Subscriber oSubscriber = (Subscriber) fetch(Subscriber.class,
				lSubscriberId, oSession);
		crit.add(Expression.eq("subscriber", oSubscriber));
		crit.add(Expression.eq("state", Integer
				.valueOf(IContactConstants.ACTIVE)));
		List lSynonyms = crit.list();
		oSession.close();
		oLogger.info("fetchSynonymBySubscriber() : exit, return Synonym List: "
				+ lSynonyms);
		return (lSynonyms);
	}
}